﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Media.Animation;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Surface.Presentation;
using Microsoft.Surface.Presentation.Controls;
using Microsoft.Surface.Presentation.Input;
using System.Collections.ObjectModel;
using navigation.Data;

namespace navigation.Contents
{
    /// <summary>
    /// Interaction logic for StoryBoardItem.xaml
    /// </summary>
    public partial class StoryBoardItem : UserControl
    {
        public StoryBoardItem()
        {
            InitializeComponent();
        }

        //private string storyName;
        //private string storyCardColor;
        //private string storySummary;

        # region Initialize Dependency Property

        public static DependencyProperty StoryNameProperty = DependencyProperty.Register("StoryName", typeof(string), typeof(StoryBoardItem));

        public string StoryName
        {
            get
            {
                return (string)GetValue(StoryBoardItem.StoryNameProperty);
            }
            set 
            {
                SetValue(StoryBoardItem.StoryNameProperty, value);
            }
        }

        public static DependencyProperty PlannedItemsProperty = DependencyProperty.Register("PlannedItems", typeof(ObservableCollection<Task>), typeof(StoryBoardItem));

        public ObservableCollection<Task> PlannedItems
        {
            get
            {
                return (ObservableCollection<Task>)GetValue(StoryBoardItem.PlannedItemsProperty);
            }
            set
            {
                SetValue(StoryBoardItem.PlannedItemsProperty, value);
            }
        }

        public static DependencyProperty InProgressItemsProperty = DependencyProperty.Register("InProgressItems", typeof(ObservableCollection<Task>), typeof(StoryBoardItem));

        public ObservableCollection<Task> InProgressItems
        {
            get
            {
                return (ObservableCollection<Task>)GetValue(StoryBoardItem.InProgressItemsProperty);
            }
            set
            {
                SetValue(StoryBoardItem.InProgressItemsProperty, value);
            }
        }

        public static DependencyProperty DoneItemsProperty = DependencyProperty.Register("DoneItems", typeof(ObservableCollection<Task>), typeof(StoryBoardItem));

        public ObservableCollection<Task> DoneItems
        {
            get
            {
                return (ObservableCollection<Task>)GetValue(StoryBoardItem.DoneItemsProperty);
            }
            set
            {
                SetValue(StoryBoardItem.DoneItemsProperty, value);
            }
        }

        #endregion
               

        // get the dragged element when touch on the task card and start moving
        private void OnDragSourcePreviewTouchDown(object sender, TouchEventArgs e)
        {
            FrameworkElement findSource = e.OriginalSource as FrameworkElement;
            SurfaceListBoxItem draggedElement = null;

            // Find the touched SurfaceListBoxItem object.
            while (draggedElement == null && findSource != null)
            {
                if ((draggedElement = findSource as SurfaceListBoxItem) == null)
                {
                    findSource = VisualTreeHelper.GetParent(findSource) as FrameworkElement;
                }
            }

            if (draggedElement == null)
            {
                return;
            }

            // Create the cursor visual.
            ContentControl cursorVisual = new ContentControl()
            {
                Content = draggedElement.DataContext,
                Style = FindResource("CursorStyle") as Style
            };

            // Add a handler. This will enable the application to change the visual cues.
            //SurfaceDragDrop.AddTargetChangedHandler(cursorVisual, OnTargetChanged);

            // Create a list of input devices. Add the touches that
            // are currently captured within the dragged element and
            // the current touch (if it isn't already in the list).
            List<InputDevice> devices = new List<InputDevice>();
            devices.Add(e.TouchDevice);
            foreach (TouchDevice touch in draggedElement.TouchesCapturedWithin)
            {
                if (touch != e.TouchDevice)
                {
                    devices.Add(touch);
                }
            }

            // Get the drag source object
            ItemsControl dragSource = ItemsControl.ItemsControlFromItemContainer(draggedElement);

            SurfaceDragCursor startDragOkay =
                SurfaceDragDrop.BeginDragDrop(
                  dragSource,                 // The SurfaceListBox object that the cursor is dragged out from.
                  draggedElement,             // The SurfaceListBoxItem object that is dragged from the drag source.
                  cursorVisual,               // The visual element of the cursor.
                  draggedElement.DataContext, // The data associated with the cursor.
                  devices,                    // The input devices that start dragging the cursor.
                  DragDropEffects.Move);      // The allowed drag-and-drop effects of the operation.

            // If the drag began successfully, set e.Handled to true. 
            // Otherwise SurfaceListBoxItem captures the touch 
            // and causes the drag operation to fail.
            e.Handled = (startDragOkay != null);
            draggedElement.Visibility = System.Windows.Visibility.Hidden;
        }

        // effect of the task card when drag into the listbox or move out, 
        // the border will change to red if the target area is not suitable to accept the card
        private void OnDropTargetDragEnter(object sender, SurfaceDragDropEventArgs e)
        {
            Task data = e.Cursor.Data as Task;

            if (data.TaskName == this.StoryName)
            {
                data.CanDrop = true;
            }
            else
            {
                data.CanDrop = false;
            }

            if (!data.CanDrop)
            {
                e.Effects = DragDropEffects.None;
            }
        }

        private void OnDropTargetDragLeave(object sender, SurfaceDragDropEventArgs e)
        {
            Task data = e.Cursor.Data as Task;

            if (data.TaskName == this.StoryName)
            {
                data.CanDrop = true;
            }
            else
            {
                data.CanDrop = false;
            }
            // Reset the effects.
            e.Effects = e.Cursor.AllowedEffects;
        }

        private void OnTargetChanged(object sender, TargetChangedEventArgs e)
        {
            if (e.Cursor.CurrentTarget != null)
            {
                Task data = e.Cursor.Data as Task;

                e.Cursor.Visual.Tag = (data.CanDrop) ? "CanDrop" : "CannotDrop";
            }
            else
            {
                e.Cursor.Visual.Tag = null;
            }
        }


        // operations for three listboxes
        // DragCanceled and DragCompleted are use to avoid the the task card goes disappear when drop card outside of the listbox
        // OnDropTargetDrop is use to add the task card into the right place
        private void PlannedListBox_DragCanceled(object sender, SurfaceDragDropEventArgs e)
        {
            Console.WriteLine("cancel");            

            foreach (Task item in PlannedListBox.Items)
            {
                SurfaceListBoxItem temp = PlannedListBox.ItemContainerGenerator.ContainerFromItem(item) as SurfaceListBoxItem;
                if (temp.Visibility == System.Windows.Visibility.Hidden)
                    temp.Visibility = System.Windows.Visibility.Visible;
            }
        }

        private void PlannedListBox_DragCompleted(object sender, SurfaceDragCompletedEventArgs e)
        {
            if (e.Cursor.CurrentTarget is LibraryStack)
            {
                PlannedItems.Remove(e.Cursor.Data as Task);
            }
            foreach (Task item in PlannedListBox.Items)
            {
                SurfaceListBoxItem temp = PlannedListBox.ItemContainerGenerator.ContainerFromItem(item) as SurfaceListBoxItem;
                if (temp.Visibility == System.Windows.Visibility.Hidden)
                    temp.Visibility = System.Windows.Visibility.Visible;
            }
        }

        private void InProgressListBox_DragCanceled(object sender, SurfaceDragDropEventArgs e)
        {
            Console.WriteLine("4");
            foreach (Task item in InProgressListBox.Items)
            {
                SurfaceListBoxItem temp = InProgressListBox.ItemContainerGenerator.ContainerFromItem(item) as SurfaceListBoxItem;
                if (temp.Visibility == System.Windows.Visibility.Hidden)
                    temp.Visibility = System.Windows.Visibility.Visible;
            }
        }

        private void InProgressListBox_DragCompleted(object sender, SurfaceDragCompletedEventArgs e)
        {
            if (e.Cursor.CurrentTarget is LibraryStack)
            {
                InProgressItems.Remove(e.Cursor.Data as Task);
            }
            foreach (Task item in InProgressListBox.Items)
            {
                SurfaceListBoxItem temp = InProgressListBox.ItemContainerGenerator.ContainerFromItem(item) as SurfaceListBoxItem;
                if (temp.Visibility == System.Windows.Visibility.Hidden)
                    temp.Visibility = System.Windows.Visibility.Visible;
            }
        }

        private void DoneListBox_DragCanceled(object sender, SurfaceDragDropEventArgs e)
        {
            foreach (Task item in DoneListBox.Items)
            {
                SurfaceListBoxItem temp = DoneListBox.ItemContainerGenerator.ContainerFromItem(item) as SurfaceListBoxItem;
                if (temp.Visibility == System.Windows.Visibility.Hidden)
                    temp.Visibility = System.Windows.Visibility.Visible;
            }
        }

        private void DoneListBox_DragCompleted(object sender, SurfaceDragCompletedEventArgs e)
        {
            if (e.Cursor.CurrentTarget is LibraryStack)
            {
                DoneItems.Remove(e.Cursor.Data as Task);
            }
            foreach (Task item in DoneListBox.Items)
            {
                SurfaceListBoxItem temp = DoneListBox.ItemContainerGenerator.ContainerFromItem(item) as SurfaceListBoxItem;
                if (temp.Visibility == System.Windows.Visibility.Hidden)
                    temp.Visibility = System.Windows.Visibility.Visible;
            }
        }

        private void PlannedListBox_OnDropTargetDrop(object sender, SurfaceDragDropEventArgs e)
        {
            if (PlannedItems.Contains(e.Cursor.Data as Task))
            {
                int index = this.GetListBoxItemCurrentIndex(PlannedListBox, e.Cursor.GetPosition);
                int indexOfDraggedElement = PlannedItems.IndexOf(e.Cursor.Data as Task);

                if (index < 0 || index > PlannedListBox.Items.Count - 1)
                {
                    Task temp = PlannedItems[indexOfDraggedElement];
                    PlannedItems.RemoveAt(indexOfDraggedElement);
                    PlannedItems.Add(temp);
                }
                else
                {

                    Task temp = PlannedItems[indexOfDraggedElement];
                    PlannedItems.RemoveAt(indexOfDraggedElement);
                    PlannedItems.Insert(index, e.Cursor.Data as Task);
                }
            }
            else
            {
                int index = this.GetListBoxItemCurrentIndex(PlannedListBox, e.Cursor.GetPosition);

                if (index < 0 || index > PlannedListBox.Items.Count - 1)
                    index = PlannedListBox.Items.Count;
                if (InProgressItems.Contains(e.Cursor.Data as Task))
                {
                    InProgressItems.Remove(e.Cursor.Data as Task);
                }
                else if (DoneItems.Contains(e.Cursor.Data as Task))
                {
                    DoneItems.Remove(e.Cursor.Data as Task);
                }
                PlannedItems.Insert(index, e.Cursor.Data as Task);
            }

        }

        private void InProgressListBox_OnDropTargetDrop(object sender, SurfaceDragDropEventArgs e)
        {
            Console.WriteLine("2");
            if (InProgressItems.Contains(e.Cursor.Data as Task))
            {
                int index = this.GetListBoxItemCurrentIndex(InProgressListBox, e.Cursor.GetPosition);
                int indexOfDraggedElement = InProgressItems.IndexOf(e.Cursor.Data as Task);

                if (index < 0 || index > InProgressListBox.Items.Count - 1)
                {
                    Task temp = InProgressItems[indexOfDraggedElement];
                    InProgressItems.RemoveAt(indexOfDraggedElement);
                    InProgressItems.Add(temp);
                }
                else
                {
                    Task temp = InProgressItems[indexOfDraggedElement];
                    InProgressItems.RemoveAt(indexOfDraggedElement);
                    InProgressItems.Insert(index, e.Cursor.Data as Task);
                }
            }
            else
            {
                int index = this.GetListBoxItemCurrentIndex(InProgressListBox, e.Cursor.GetPosition);

                if (index < 0 || index > InProgressListBox.Items.Count - 1)
                    index = InProgressListBox.Items.Count;
                if (PlannedItems.Contains(e.Cursor.Data as Task))
                {
                    PlannedItems.Remove(e.Cursor.Data as Task);
                }
                else if (DoneItems.Contains(e.Cursor.Data as Task))
                {
                    DoneItems.Remove(e.Cursor.Data as Task);
                }
                InProgressItems.Insert(index, e.Cursor.Data as Task);
            }

        }

        private void DoneListBox_OnDropTargetDrop(object sender, SurfaceDragDropEventArgs e)
        {
            if (DoneItems.Contains(e.Cursor.Data as Task))
            {
                int index = this.GetListBoxItemCurrentIndex(DoneListBox, e.Cursor.GetPosition);
                int indexOfDraggedElement = DoneItems.IndexOf(e.Cursor.Data as Task);

                if (index < 0 || index > DoneListBox.Items.Count - 1)
                {
                    Task temp = DoneItems[indexOfDraggedElement];
                    DoneItems.RemoveAt(indexOfDraggedElement);
                    DoneItems.Add(temp);
                }
                else
                {
                    Task temp = DoneItems[indexOfDraggedElement];
                    DoneItems.RemoveAt(indexOfDraggedElement);
                    DoneItems.Insert(index, e.Cursor.Data as Task);
                }
            }
            else
            {
                int index = this.GetListBoxItemCurrentIndex(DoneListBox, e.Cursor.GetPosition);

                if (index < 0 || index > DoneListBox.Items.Count - 1)
                    index = DoneListBox.Items.Count;
                if (PlannedItems.Contains(e.Cursor.Data as Task))
                {
                    PlannedItems.Remove(e.Cursor.Data as Task);
                }
                else if (InProgressItems.Contains(e.Cursor.Data as Task))
                {
                    InProgressItems.Remove(e.Cursor.Data as Task);
                }
                DoneItems.Insert(index, e.Cursor.Data as Task);
            }

        }

        // controls to help swap and insert task cards inside the listbox
        public delegate Point GetDragDropPosition(IInputElement theElement);

        private bool isTheCursorOnTarget(Visual target, GetDragDropPosition pos)
        {
            Rect posBounds = VisualTreeHelper.GetDescendantBounds(target);
            Point theCursorPos = pos((IInputElement)target);
            return posBounds.Contains(theCursorPos);
        }

        private ListBoxItem GetListBoxItem(ListBox listBox, int index)
        {
            if (listBox.ItemContainerGenerator.Status != System.Windows.Controls.Primitives.GeneratorStatus.ContainersGenerated)
                return null;
            return listBox.ItemContainerGenerator.ContainerFromIndex(index) as ListBoxItem;
        }

        private int GetListBoxItemCurrentIndex(ListBox listBox, GetDragDropPosition pos)
        {
            int curIndex = -1;
            for (int i = 0; i < listBox.Items.Count; i++)
            {
                ListBoxItem item = GetListBoxItem(listBox, i);
                if (isTheCursorOnTarget(item, pos))
                {
                    curIndex = i;
                    break;
                }
            }
            return curIndex;
        }

    }
}
